package com.google.code.swingonfire.utility.date;

import java.awt.Graphics2D;
import java.awt.geom.Rectangle2D;
import java.util.Calendar;

import com.google.code.swingonfire.utility.Utils;

abstract class AbstractDateRenderPart implements DateRendererPart
{

    private final DateRenderer info;

    private DateFormatStyle style;

    private Rectangle2D maximumBounds;
    private Rectangle2D bounds;
    private double x = Double.NaN;

    public AbstractDateRenderPart(DateRenderer info)
    {
        super();

        this.info = info;
    }

    public DateRenderer getInfo()
    {
        return info;
    }

    public DateFormatStyle getStyle()
    {
        return style;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public boolean setStyle(DateFormatStyle style)
    {
        if (!Utils.equals(this.style, style))
        {
            this.style = style;
            resetCachedValues();

            return true;
        }

        return false;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public void resetCachedValues()
    {
        maximumBounds = null;
        bounds = null;
        x = Double.NaN;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public Rectangle2D getMaximumBounds()
    {
        if (maximumBounds == null)
        {
            maximumBounds = computeMaximumBounds(info.getContext(), style);
        }

        return maximumBounds;
    }

    protected abstract Rectangle2D computeMaximumBounds(DateRendererContext context, DateFormatStyle style);

    /**
     * {@inheritDoc}
     */
    @Override
    public Rectangle2D getBounds(double x)
    {
        if (this.x != x)
        {
            resetCachedValues();
            this.x = x;
        }

        if (bounds == null)
        {
            bounds = computeBounds(info.getContext(), style, x);
        }

        return bounds;
    }

    protected Rectangle2D computeBounds(DateRendererContext context, DateFormatStyle style, double x)
    {
        Rectangle2D maximumBounds = getMaximumBounds();

        return new Rectangle2D.Double(maximumBounds.getX() + x, maximumBounds.getY(), maximumBounds.getWidth(),
            maximumBounds.getHeight());
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public double render(Graphics2D g, Calendar calendar, double x)
    {
        Rectangle2D bounds = getBounds(x);
        String value = getValue(info.getContext(), style, calendar);

        g.drawString(value, (int) x, 0);

        return x + bounds.getWidth();
    }

    protected abstract String getValue(DateRendererContext context, DateFormatStyle style, Calendar calendar);

    protected static Rectangle2D findMaximumBounds(DateRendererContext context, String[] values)
    {
        Rectangle2D maximumBounds = null;

        for (String value : values)
        {
            Rectangle2D bounds = context.getFont().getStringBounds(value, context.getFontRenderContext());

            if (maximumBounds == null)
            {
                maximumBounds = bounds;
            }
            else
            {
                maximumBounds = maximumBounds.createUnion(bounds);
            }
        }

        return maximumBounds;
    }

}
